package com.link.base.base.contract.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.link.base.base.accnt.model.Account;
import com.link.base.base.accnt.service.AccountService;
import com.link.base.base.approval.model.Flow;
import com.link.base.base.approval.service.FlowService;
import com.link.base.base.common.model.Attachment;
import com.link.base.base.common.service.AttachmentService;
import com.link.base.base.contract.dao.mybatis.mapper.ModContractMapper;
import com.link.base.base.contract.model.*;
import com.link.base.base.esb.service.LinkBaseDataApiService;
import com.link.base.core.util.SerialUtil;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.basic.service.ServiceException;
import com.link.core.cllog.LCLogger;
import com.link.core.util.RedisUtil;
import com.link.core.util.StringUtils;
import com.link.core.util.redisclient.LinkRedisClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 价格模具合同
 *
 * @author 阳晓琳
 * @date 2020-10-13 14:08:15
 */
@Service
public class ModContractServiceImpl extends BasicServiceImpl<ModContract> implements ModContractService {

    @Resource
    private ModContractMapper    modContractMapper;

    @Resource
    private FlowService flowService;

    @Resource
    private ContractItemService contractItemService;

    @Resource
    private ModCostChangeService modCostChangeService;

    @Resource
    private AttachmentService attachmentService;

    @Resource
    private PriContItemService priContItemService;

    @Resource
    private AccountService accountService;

    @Resource
    private ModReceivableService modReceivableService;

    @Resource
    private PriContraSignService priContraSignService;

    @Resource
    private LinkBaseDataApiService linkBaseDataApiService;

    @Override
    public BasicMapper<ModContract> getBasicMapper() {
        return modContractMapper;
    }

    /**
     * 失效按钮。合同状态变为失效
     * @param entity
     * @throws Exception
     */
    @Override
    public void unactiveContract(ModContract entity) throws Exception {
        //点击失效按钮，将合同状态变为失效
        entity.setContractStatus("Invalid");
        modContractMapper.update(entity);
    }


    /**
     * 价格模具合同点击审批按钮，创建审批流
     * 价格 模具合同提交审批前校验附件，产品行
     * 0430新增 价格合同审批前校验签订计划行
     * @param entity
     * @throws Exception
     */
    @Override
    public void priceModSubmit(ModContract entity) throws Exception {
        ModContract modContract = modContractMapper.queryById(entity);

        //价格合同 模具合同审批前校验是否有附件
        //根据合同id去附件表查询记录
        Attachment atta = new Attachment();
        atta.setHeadId(modContract.getId());
        List<Attachment> attachments = attachmentService.queryAttachmentByHeadId(atta);
        if (attachments == null || attachments.isEmpty()) {
            throw new ServiceException("IYUCONTRACT-001");
        }

        //创建审批流
        String approvalType = "PriceSubmit";
        String approvalType2 = "ModSubmit";
        ObjectMapper mapper = new ObjectMapper();
        //把Java对象转化成json字符串
        String approvalDetail = mapper.writeValueAsString(modContract);
        if ( "PriceCon".equals(modContract.getContractType())) {
            //价格合同审批前校验产品价格信息
            PriContItem priCont = new PriContItem();
            priCont.setContractId(modContract.getId());
            List<PriContItem> priContItems = priContItemService.queryAll(priCont);
            if (priContItems == null || priContItems.isEmpty()) {
                throw new ServiceException("IYUCONTRACT-003");
            }


            //1.判断上次价格合同有没有未超期签订计划
            if ("N".equals(modContract.getFstPriFlag())) {
                String lastPriId = modContract.getLastPriId() == null ? "null" : String.valueOf(modContract.getLastPriId());
                if ("null".equals(lastPriId)) {
                    //不是首次签订合同，但是上年度价格合同ID没关联上 抛出异常 "上年度价格合同关联异常，请联系管理员！"
                    throw new ServiceException("IYUCONTRACT-012");
                }
                //直接根据本合同的上年度价格合同ID去签订计划表查询记录
                PriContraSign querSign = new PriContraSign();
                querSign.setPriContraId(modContract.getLastPriId());
                List<PriContraSign> priLastSigns = priContraSignService.queryAll(querSign);
                String isOverTimeLast = "notN";
                for (PriContraSign priLastSign : priLastSigns) {
                    //如果这条记录是否超期为否，就为这个变量赋值haveN,结束循环
                    if ("N".equals(priLastSign.getIsOvertime())) {
                        isOverTimeLast = "haveN";
                        break;
                    }
                }
                if (!"haveN".equals(isOverTimeLast)) {
                    //说明上年度价格合同没有是否超期为否的记录 抛错 请先制定上一年度该价格合同的签订计划，再提交审批
                    throw new ServiceException("IYUCONTRACT-013");
                }
            }

            //2.价格合同审批前校验 是否存在未超期的签订计划行
            //20210528【是否续签】选是时，提交时触发价格合同签订计划的校验。选否时，不校验签订计划。
            if ("Y".equals(modContract.getNextSignTime())) {
                //1.判断本合同是否存在未超期行
                PriContraSign querySign = new PriContraSign();
                querySign.setPriContraId(modContract.getId());
                List<PriContraSign> priContraSigns = priContraSignService.queryAll(querySign);
                String isOverTime = "notN";
                if (priContraSigns == null || priContraSigns.isEmpty()) {
                    //说明没查到任何签订计划 至少应该存在一条未超期计划 抛错 请先制定下次价格合同签订计划，再提交审批!
                    throw new ServiceException("IYUCONTRACT-011");
                }
                for (PriContraSign priContraSign : priContraSigns) {
                    //如果这条记录是否超期为否，就为这个变量赋值haveN,结束循环
                    if ("N".equals(priContraSign.getIsOvertime())) {
                        isOverTime = "haveN";
                        //20210608新增 价格合同提交审批，对应的未超期的签订计划行赋值审批中
                        priContraSign.setSubmitStatus("InApproval");
                        priContraSignService.update(priContraSign);
                        break;
                    }
                }
                if (!"haveN".equals(isOverTime)) {
                    //说明没有是否超期为否的记录 抛错 请先制定下次价格合同签订计划，再提交审批!
                    throw new ServiceException("IYUCONTRACT-011");
                }
            }



            //创建价格合同审批流
            flowService.createFlow(modContract.getId(),approvalType,null,modContract.getContractName(),modContract.getId(),approvalDetail);
        } else {
            //模具合同审批前校验是否有产品行
            ContractItem conItem = new ContractItem();
            conItem.setContractId(modContract.getId());
            List<ContractItem> contractItems = contractItemService.queryAll(conItem);
            if (contractItems == null || contractItems.isEmpty()) {
                throw new RuntimeException("模具合同缺失产品行!");
            }
            //创建模具合同审批流
            flowService.createFlow(modContract.getId(),approvalType2,null,modContract.getContractName(),modContract.getId(),approvalDetail);
        }
        modContract.setContractStatus("Submitted");
        modContractMapper.update(modContract);
    }

    /**
     * 价格模具合同审批通过
     * @param flow
     * @param arg1
     * @param arg2
     * @param arg3
     * @param arg4
     * @param arg5
     * @throws Exception
     */
    @Override
    public void agreeApproval(Flow flow, String arg1, String arg2, String arg3, String arg4, String arg5) throws Exception {
        Long modContractId = flow.getFlowObjId();
        ModContract modContract = new ModContract();
        modContract.setId(modContractId);
        ModContract modContract1 = modContractMapper.queryById(modContract);
        modContract1.setContractStatus(arg1);
        modContractMapper.update(modContract1);
        //模具合同提交审批通过后，合同状态已生效，将该模具合同的产品信息插入到定点合同产品价格追踪表
        if ("ModelCon".equals(modContract1.getContractType())) {
            if ("Effect".equals(modContract1.getContractStatus())) {
                //1.根据上面拿到的模具合同id去产品表查询产品记录
                ContractItem conItem = new ContractItem();
                conItem.setContractId(modContract1.getId());
                List<ContractItem> contractItems = contractItemService.queryAll(conItem);
                //2.遍历产品记录，模具合同头名称，合同类型，定点合同ID插入到产品价格追踪表
                //新增：遍历产品记录，将产品id，模具合同id，审批状态默认新建 插入到模具回款表
                ModCostChange modCost = new ModCostChange();
                ModReceivable modReceivable = new ModReceivable();
                if (contractItems != null && !contractItems.isEmpty()) {
                    for (ContractItem contractItem : contractItems) {
                        //向定点合同 产品价格追踪表 插入记录
                        modCost.setId(keyGenerateService.keyGenerate());
                        modCost.setCrmPartId(contractItem.getCrmPartId());
                        modCost.setSoftMoldFee(contractItem.getSoftFee());
                        modCost.setFormalModCost(contractItem.getOffcialFee());
                        modCost.setBelongContract(modContract1.getContractName());
                        modCost.setBelongContractTpye(modContract1.getContractType());
                        modCost.setSignType(modContract1.getSignType());
                        modCost.setPointContractId(modContract1.getFixContId());
                        //来源的模具合同id
                        modCost.setModContractId(modContract1.getId());
                        modCost.setPartName(contractItem.getPartName());
                        modCost.setPartNumber(contractItem.getPartCode());
                        modCostChangeService.insert(modCost);

                        //向模具回款表 插入每个产品回款记录
                        modReceivable.setId(keyGenerateService.keyGenerate());
                        modReceivable.setPartModId(contractItem.getId()); //产品id
                        modReceivable.setModContractId(contractItem.getContractId());
                        modReceivable.setApprovalStatus("New");
                        modReceivableService.insert(modReceivable);
                        modReceivable.setCreatedBy(modContract1.getCreatedBy());  //创建人ID默认为审批流发起人，确保本模具回款计划被发起人看见
                        modReceivableService.updateCreatedBy(modReceivable);
                    }
                }
            }
        }

        //价格合同审批通过
        if ("PriceCon".equals(modContract1.getContractType())) {

            //价格合同生效
            if ("Effect".equals(modContract1.getContractStatus())) {
                changeItemStatus(modContract1);
                //价格合同生效，调用接口同步价格合同头行信息至ERP
                linkBaseDataApiService.syncPriContract(modContract1);
            }

            //价格合同拒绝或撤回 修改是否超期为否的签订计划审批状态
            if ("Rejected".equals(modContract1.getContractStatus()) || "New".equals(modContract1.getContractStatus())) {
                //价格合同生效，调用接口同步价格合同头行信息至ERP
                changeItemStatus(modContract1);
            }

            //1.不是首次签订,为上次价格合同的没有超期的计划行赋值实际签订时间
            if ("N".equals(modContract1.getFstPriFlag())) {
                //根据本次价格合同的上年度价格合同ID，去签订计划表查询对应记录
                PriContraSign querSign = new PriContraSign();
                querSign.setPriContraId(modContract1.getLastPriId());
                List<PriContraSign> priLastSigns = priContraSignService.queryAll(querSign);
                for (PriContraSign priLastSign : priLastSigns) {
                    //未超期的计划，为实际签订时间赋值本合同审批通过时间
                    if ("N".equals(priLastSign.getIsOvertime())) {
                        priLastSign.setNextActSignDate(modContract1.getLastUpdated());
                        priContraSignService.update(priLastSign);
                        break;
                    }
                }
            }
        }
    }

    public void changeItemStatus(ModContract modContract1) throws Exception {
        //20210608新增 价格合同生效，对应的未超期的签订计划行赋值审批通过,合同撤回或拒绝，赋值新建
        //1.查询本合同的未超期签订计划
        PriContraSign querySign = new PriContraSign();
        querySign.setPriContraId(modContract1.getId());
        List<PriContraSign> priContraSigns = priContraSignService.queryAll(querySign);
        if (priContraSigns == null || priContraSigns.isEmpty()) {
            //说明没查到任何签订计划 至少应该存在一条未超期计划 抛错 : 该价格合同未创建下次合同签订计划，请通知提交人撤回审批，补充签订计划！
            throw new ServiceException("IYUCONTRACT-014");
        }
        //遍历本合同的签订计划，只要遇到未超期计划，直接赋值已审批
        for (PriContraSign priContraSign : priContraSigns) {
            //如果这条记录是否超期为否，就为这个变量赋值haveN,结束循环
            if ("N".equals(priContraSign.getIsOvertime())) {
                // 价格合同撤回或拒绝，对应的未超期的签订计划行赋值新建
                if ("Rejected".equals(modContract1.getContractStatus()) || "New".equals(modContract1.getContractStatus())) {
                    priContraSign.setSubmitStatus("New");
                }
                // 价格合同生效，对应的未超期的签订计划行赋值已审批
                if ("Effect".equals(modContract1.getContractStatus())) {
                    priContraSign.setSubmitStatus("Approved");
                }
                priContraSignService.update(priContraSign);
                break;
            }
        }
    }

    /**
     * 价格合同点击保存时，校验是否首次签订字段，为Y时，上年度价格合同id置空，为N时，在选择了上年度价格合同后，根据合同id拿到原价格合同的定点合同id存值
     * @param entity
     * @throws Exception
     */
    @Override
    public void beforUpsert(ModContract entity) throws Exception {
        super.beforUpsert(entity);
        if ("PriceCon".equals(entity.getContractType())) {
            //为Y时，上年度价格合同id置空(避免用户在编辑合同头时重复来回切换picklist插入无效数据)
            if ("Y".equals(entity.getFstPriFlag())) {
                entity.setLastPriId(null);
            } else if ("N".equals(entity.getFstPriFlag())) {
                //为N时，在选择了上年度价格合同后，根据合同id拿到原价格合同的定点合同id存值
                ModContract modCon = new ModContract();
                modCon.setId(entity.getLastPriId());
                ModContract modContract = modContractMapper.queryById(modCon);
                if (modContract != null) {
                    entity.setFixContId(modContract.getFixContId());
                }
            }
        }
    }

    @Override
    public void beforInsert(ModContract entity) throws Exception {
        if (StringUtils.isNull(entity.getDocNo())) {
            entity.setDocNo(SerialUtil.getContractTodayNextCurrentSerial(entity.getContractType()));
        }

        //合同编码自动生成
        //1.获取客户编码 (根据客户id查询)
        Account accountModel = new Account();
        accountModel.setId(entity.getAcctId());
        Account account = accountService.queryById(accountModel);
        if (account == null) {
            throw new ServiceException("IYUCONTRACT-006");
        }
        String acctCode = account.getAcctCode();
        //2.判断合同类型获取字符
        String contractType;
        if ("FrameCon".equals(entity.getContractType())) {
            //框架合同字符编码
            contractType = "KJ";
        } else if ("SentinelCon".equals(entity.getContractType())) {
            //定点合同字符编码
            contractType = "DD";
        } else if ("ModelCon".equals(entity.getContractType())) {
            //模具合同字符编码
            contractType = "MJ";
        } else {
            //价格合同字符编码
            contractType = "JG";
        }
        //3.获取年月日字符串
        Date today = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        //将日期格式化为日期/时间字符串
        String day = format.format(today);
        //4.流水号生成（每个客户每年刷新一回,换一次key，就会重新计数一次）
        Calendar thisYear = Calendar.getInstance();
        String year = String.valueOf(thisYear.get(Calendar.YEAR));
        LinkRedisClient jedis = RedisUtil.getJedis();
        String zeroCode;
        try {
            //判断redisKey是否存在
            String redisKey = "contract_code" + "/" + year;
            if (jedis.exists(redisKey)) {
                if (jedis.hexists(redisKey,acctCode + "/" + contractType)) {
                    //存在则流水号取出+1
                    String getCode = jedis.hget(redisKey,acctCode + "/"  + contractType);
                    int code = Integer.parseInt(getCode);
                    //四位流水号补零
                    zeroCode = String.format("%04d",code);
                    //使用后+1
                    jedis.hincrBy(redisKey,acctCode + "/" + contractType,1);
                } else {
                    //不存在则说明当前为该客户今年第一个该类型的合同
                    zeroCode = String.format("%04d",1);
                    jedis.hset(redisKey,acctCode + "/"  + contractType, String.valueOf(2));
                }
            } else {
                //redisKey不存在去数据库查开头客户编号为acctCode，合同类型为conracttype的当年流水号排到哪
                List<ModContract> contracts = modContractMapper.queryByContractCode(acctCode,contractType);
                if (contracts.size() != 0) {
                    //存在则在最新客户合同记录编号尾数的基础上+1
                    String theAcctcode = contracts.get(0).getAcctContCode();
                    //取最新合同记录的合同编号的后四位流水号并+1塞入zerocode
                    int theCode = Integer.parseInt(theAcctcode.substring(theAcctcode.length() - 4));
                    ++theCode;
                    zeroCode = String.format("%04d", theCode);
                    //重新为jedis塞入值再+1
                    jedis.hset(redisKey,acctCode + "/" + contractType,zeroCode);
                    jedis.hincrBy(redisKey,acctCode + "/" + contractType,1);
                } else {
                    //不存在则说明当前为该客户今年第一个合同
                    zeroCode = String.format("%04d",1);
                    jedis.hset(redisKey,acctCode + "/" + contractType, String.valueOf(2));
                }
            }
            entity.setAcctContCode(acctCode + contractType + day + zeroCode);
        } catch (Exception e) {
            LCLogger.withException(e);
        } finally {
            RedisUtil.returnResource(jedis);
        }
    }

    /**
     * 根据价格合同ID，查找本价格合同的所有订单合同的所有项目ID
     * @param querPri
     * @return
     */
    @Override
    public List<ModContract> queryProjectIds(ModContract querPri) {
        return modContractMapper.queryProjectIds(querPri);
    }

    @Override
    public void changeContractStatusToNew(ModContract entity) throws Exception {
        modContractMapper.changeContractStatusToNew(entity);
    }
}
